program define swapval
*! 1.0.1 NJC 24 November 1999 
	version 6.0 
	
	gettoken a 0 : 0 
	unab varlist : `a', min(1) max(2) 
	local nvars : word count `varlist' 

	if `nvars' == 1 { 
		gettoken b 0 : 0 
		unab varlist: `a' `b', min(2) max(2) 
	}
	
	tokenize `varlist' 
	args a b
	
	capture confirm string variable `a' 
	local aisnum = _rc > 0 
	capture confirm string variable `b'
	local bisnum = _rc > 0 
	if `aisnum' != `bisnum' { 
		di in r "variables must be compatible types" 
		error 109 
	} 

	gettoken inif 0 : 0 
	if "`inif'" != "in" & "`inif'" != "if"  & "`inif'" != "" { 
		di in r "incorrect syntax" 
		exit 198 
	}

	if "`inif'" == "in" {
		local n = _N 
		if index("`0'", "l") { 
			local 0 : subinstr local 0 "l" "`n'" 
		}
		if index("`0'", "f") { 
			local 0 : subinstr local 0 "f" "1" 
		}	
		numlist "`0'", int range(>=-`n' <=`n') sort  
	        	
		chkzero `r(numlist)'  

		tokenize `r(numlist)' 
	} 
	else if "`inif'" == "if"  { 
	* test whether `if' condition is acceptable 
		qui count if `0' 
		if r(N) == 0 { 
			di in r "no observations" 
			exit 2000 
		} 	
		else local if "if `0'" 
	}

	nobreak { 

	if "`inif'" == "in" { 
		if `aisnum' { /* both variables numeric */ 
		* I'm guessing here using locals, rather than copying 
		* all values for variable, is usually quicker 
			qui while "`1'" != "" {
				local 1 = cond(`1' < 0, `n'+`1'+1, `1') 
				local copy = `b'[`1'] 
				replace `b' = `a' in `1' 
				replace `a' = `copy' in `1' 
				mac shift 
			} 
		} 
		else { /* both variables string */ 
		* copy variable to keep leading and trailing spaces 
			tempvar copy 
			local btype : type `b' 
			qui gen `btype' `copy' = `b' 
			qui while "`1'" != "" { 
				replace `b' = `a' in `1' 
				replace `a' = `copy' in `1' 
				mac shift 
			} 	
		} 
	}  

	else if "`inif'" == "if" { /* if */ 
		tempvar copy 
		local btype : type `b' 
		qui gen `btype' `copy' = `b' 
		qui replace `b' = `a' `if' 
		qui replace `a' = `copy' `if' 
	} 	

	else { 
	* < nothing > => swapping whole variables, so just -rename-  
		tempname copy 
		rename `b' `copy' 
		rename `a' `b' 
		rename `copy' `a' 
	} 	

	} /* end nobreak */ 
	
	qui compress `a' `b' 
		
end 

program def chkzero 
* 1.0.1 NJC 24 November 1999 
* The arguments are sorted. 
* If the first is >0, we need do nothing but exit gracefully. 
* If the first is 0, we have found a zero. 
* If the first is <0, we search our way past the - elements. 
* Thanks to Bill Gould for an improvement.
	if `1' > 0 { 
		exit 0 
	}	
	else if `1' == 0 { 
		di in r "0 invalid obs no" 
		exit 198 
	} 
	else {  
		local i = 1  
		local nnum : word count `0' 
		while ``i'' < 0 & `i' < `nnum' {
			local i = `i' + 1 
			if ``i'' == 0 { 
				di in r "0 invalid obs no"
				exit 198 
			}
		}	
	}
end 
		
